<template>
  <div class="o-image-viewer" :style="showAnimation">
    <div class="image-btns">
      <Icon type="ios-close" class="btn" @click="close" />
      <Icon type="ios-sync" class="btn" @click="rotateImage" />
    </div>
    <div class="image-cover">
      <img
        ref="image"
        id="zoomImage"
        :src="imageSrc"
        @load="revokeObjectURL()"
        :style="imageStyle"
        @mousedown.prevent="startDrag"
      />
    </div>
  </div>
</template>

<script lang="ts">
import { T_srv, ts, Tsrv, vue } from '@/services';

@T_srv.comp
export default class oImageViewer extends vue {
  @T_srv.prop({
    required: true
  })
  config: any;

  @T_srv.prop({
    type: Number,
    default: 0
  })
  id: string;

  private imageSrc: string = '';

  private showAnimation = {};

  public revokeObjectURL: () => void;

  // 缩放参数
  private scale: number = 1;

  private translateX: number = 0;

  private translateY: number = 0;

  // 拖拽状态
  private isDragging: boolean = false;

  private dragStartX: number = 0;

  private dragStartY: number = 0;

  private rotation: number = 0;

  // 计算图片样式
  get imageStyle() {
    return {
      transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale}) rotate(${this.rotation}deg)`,
      transition: 'transform 0.1s ease-out'
    };
  }

  mounted() {
    this.show();
    this.initEventListeners();
    this.centerImage();
  }

  private init() {
    if (!Tsrv.noValue(this.config?.imageSrc)) {
      this.imageSrc = this.config.imageSrc;
      this.revokeObjectURL = () => {};
      return;
    }
    // this.imageSrc = Tsrv.utils.getFileSrc(this.config.id, false);
    const dwn = new ts.T_downloadArg();
    dwn.setFileName(this.config.imageValue.libFileName).setPath('image');

    Tsrv.download(dwn)
      .then(r => {
        if (!r.err) {
          this.imageSrc = r.url;
          this.revokeObjectURL = r.revokeObjectURL;
        } else {
          this.$msg(r.err);
        }
      })
      .catch(err => {
        this.$msg(err);
      });
  }

  // 打开界面
  public show() {
    const that = this;
    this.showAnimation = {
      display: 'block',
      // 'z-index': 102 + this.id
      'z-index': 202 + this.id
    };
    this.init();
    setTimeout(() => {
      that.showAnimation = {
        display: 'block',
        opacity: 1,
        // 'z-index': 102 + this.id
        'z-index': 202 + this.id
      };
    }, 10);
  }

  /**
   * 关闭界面
   */
  public close() {
    const that = this;
    this.showAnimation = {
      display: 'block',
      opacity: 0,
      // 'z-index': 102 + this.id
      'z-index': 202 + this.id
    };
    setTimeout(() => {
      that.showAnimation = {
        display: 'none',
        // 'z-index': 102 + this.id
        'z-index': 202 + this.id
      };
      this.$bus.$emit(`modal_${this.id}`, null);
    }, 200);
  }

  beforeDestroy() {
    this.removeEventListeners();
  }

  // 初始化事件监听
  private initEventListeners() {
    const imgElement = this.$refs.image as HTMLElement;

    // 滚轮事件
    imgElement.addEventListener('wheel', this.handleWheel, { passive: false });

    // 全局鼠标事件
    document.addEventListener('mousemove', this.handleDrag);
    document.addEventListener('mouseup', this.stopDrag);

    // Esc事件
    document.addEventListener('keydown', this.handleEsc);
  }

  // 移除事件监听
  private removeEventListeners() {
    const imgElement = this.$refs.image as HTMLElement;

    imgElement.removeEventListener('wheel', this.handleWheel);
    document.removeEventListener('mousemove', this.handleDrag);
    document.removeEventListener('mouseup', this.stopDrag);
    document.removeEventListener('keydown', this.handleEsc);
  }

  // 居中图片
  private centerImage() {
    this.$nextTick(() => {
      const container = this.$refs.container as HTMLElement;
      const imgElement = this.$refs.image as HTMLImageElement;

      if (container && imgElement) {
        this.translateX = (container.offsetWidth - imgElement.width) / 2;
        this.translateY = (container.offsetHeight - imgElement.height) / 2;
      }
    });
  }

  private rotateImage(): void {
    this.rotation += 90;
    // 如果超过 360°，归零（可选）
    // if (this.rotation >= 360) {
    //   this.rotation = 0;
    // }
  }

  // Esc 事件处理
  private handleEsc(e: KeyboardEvent) {
    e.preventDefault();
    if (e.key === 'Escape') {
      this.close();
    }
  }

  // 滚轮事件处理
  private handleWheel(e: WheelEvent) {
    e.preventDefault();

    const imgElement = this.$refs.image as HTMLImageElement;
    const rect = imgElement.getBoundingClientRect();

    // 计算鼠标相对位置
    const mouseX = (e.clientX - rect.left) / this.scale - this.translateX;
    const mouseY = (e.clientY - rect.top) / this.scale - this.translateY;

    // 计算缩放比例
    const delta = e.deltaY > 0 ? 0.9 : 1.1;
    const newScale = this.scale * delta;

    // 限制缩放范围
    if (newScale < 0.1 || newScale > 10) return;

    // 计算新的位移
    this.translateX = (this.translateX + mouseX) * (1 / delta) - mouseX;
    this.translateY = (this.translateY + mouseY) * (1 / delta) - mouseY;
    this.scale = newScale;
  }

  // 开始拖拽
  private startDrag(e: MouseEvent) {
    this.isDragging = true;
    this.dragStartX = e.clientX - this.translateX;
    this.dragStartY = e.clientY - this.translateY;
  }

  // 处理拖拽
  private handleDrag(e: MouseEvent) {
    if (!this.isDragging) return;

    this.translateX = e.clientX - this.dragStartX;
    this.translateY = e.clientY - this.dragStartY;
  }

  // 停止拖拽
  private stopDrag() {
    this.isDragging = false;
  }
}
</script>

<style lang="scss" scoped>
.image-btns {
  position: absolute;
  right: 20px;
  top: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
.btn {
  color: #fff;
  font-size: 30px;
  font-weight: bold;
  cursor: pointer;
  background-color: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  z-index: 1;
}
.o-image-viewer {
  position: absolute;
  z-index: 1001;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  opacity: 0;
  display: none;
  transition: ease-in-out 0.2s;
  background-color: rgba(0, 0, 0, 0.5);
  .image-cover {
    padding: 20px;
    height: 100%;
    width: 100%;
    overflow: hidden;
    // position: relative;
    img {
      width: calc(100% - 40px);
      height: calc(100% - 40px);
      object-fit: contain;
      object-fit: cover;
    }
    #zoomImage {
      position: absolute;
      transform-origin: 0 0; /* 重置缩放原点 */
      // transition: transform 0.1s ease-out;
      cursor: grab;
      transform-origin: center;
    }
    #zoomImage:active {
      cursor: grabbing;
    }
  }
}
</style>
